﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace FileClient
{
    public partial class MainWindow : Form
    {
        public MainWindow()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
        }
        
        private void MainWindow_Load(object sender, EventArgs e)
        {
            ProgressLabel.Text = String.Empty;
            Config.splash = new Splash(this);
            Config.splash.Show();
            Opacity = 0;
            ShowInTaskbar = false;
        }

        public void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            RemoteList.Enabled = false;
            pictureBox1.ImageLocation = Config.PosterImage((string)RemoteList.SelectedItem);
            synopsisTextbox.Text = Config.Synopsis((string)RemoteList.SelectedItem);
            RemoteList.Enabled = true;
            Download.Enabled = true;
        }

        public void Download_Click(object sender, EventArgs e)
        {
            RemoteList.Enabled = false;

            StateObject state = new StateObject();
            var cSocket = new TcpClient();
            byte[] buffer;
            String FilePath;

            try
            {
                cSocket.Connect(Config.ipaddress[Config.IP], 5330);

                if (cSocket.Connected)
                {
                    cSocket.Client.Send(Encoding.ASCII.GetBytes("*Request|" + RemoteList.SelectedItem));
                    int length = cSocket.Client.Receive(buffer=new byte[1024]);
                    FilePath = Encoding.ASCII.GetString(buffer, 0, length);
                }
                else return;
            }
            catch
            {
                MessageBox.Show("Server is currently down.\nUnable to download file");
                throw;
            }

            new Thread(Receive_File).Start((object)FilePath);
        }

        private void Refresh_Click(object sender, EventArgs e)
        {
            new Thread(Receive_List).Start();
        }

        int XPos = 0; int YPos = 0; Boolean Switch = false; int num = 600;
        public void timer2_Tick(object sender, EventArgs e)
        {
            if (num == XPos)
            {
                if (num == 600) Switch = true;
                if (num == -7) Switch = false;

                this.Marqee.Location = new System.Drawing.Point(0, YPos);
                if (Switch) num = -7;
                if (!Switch) num = 600;
            }
            else
            {
                this.Marqee.Location = new System.Drawing.Point(XPos, YPos);
                if (Switch) XPos -= 1;
                if (!Switch) XPos += 1;
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (!Config.Good2Go) new Thread(StartupCheck).Start();
            else
            {
                Config.splash.Hide();
                this.Opacity = 100;
                this.ShowInTaskbar = true;
                new Thread(Connection).Start();
                timer1.Enabled = false;
            }
        }
        private void latencytimer_Tick(object sender, EventArgs e)
        {
            latency.Text = "Latency: " + ping + " ms";
            new Thread(TimerCode).Start();
            //TimerCode();
        }
        private void TimerCode()
        {
            Stopwatch watch = new Stopwatch();
            TcpClient tcp = new TcpClient();
            try
            {
                if (Config.Good2Go)
                {
                    tcp.Connect(Config.ipaddress[Config.IP], 5331);
                    byte[] buffer = new byte[10];

                    watch.Restart();
                    tcp.Client.Send(Encoding.ASCII.GetBytes("PING"));
                    int size = tcp.Client.Receive(buffer);
                    watch.Stop();

                    String content = Encoding.ASCII.GetString(buffer, 0, size);
                    if (content == "PONG") ping = watch.ElapsedMilliseconds;
                }
                
                tcp.Close(); 
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lost connection to the server", "Lost Connection");
                Environment.Exit(-1);
            }
        }
        double ping = 00.0;

        private void SearchBox_TextChanged(object sender, EventArgs e)
        {
            //new Thread(Search).Start();
            Search();
        }

        private void Search()
        {
            List<string> found = new List<string>();
            RemoteList.Items.Clear();
            
            for (int i = 0; i < Config.FileList.Count; i++)
            {
                String file = Config.FileList[i].ToString().ToLower();
                if (file.Replace("_", " ").Contains(SearchBox.Text.ToLower()))
                {
                    RemoteList.Items.Add(Config.FileList[i].ToString());
                }
            }
        }

        public void Form1_FormClosing(object sender, FormClosingEventArgs e)
        { Environment.Exit(-1); }

        #region SocketRegion
        public void StartupCheck()
        {
            TcpClient tcp = new TcpClient();
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[10];
                    tcp.Connect(Config.ipaddress[Config.IP], 5331);
                    tcp.Client.Send(Encoding.ASCII.GetBytes("PING"));
                    int size = tcp.Client.Receive(buffer);
                    String content = Encoding.ASCII.GetString(buffer, 0, size);

                    if (content == "PONG") Config.Good2Go = true;

                    tcp.Close();
                    return;
                }
                catch (Exception)
                {
                    Config.Good2Go = false;
                    tcp.Close();
                    return;
                }
            }
        }
        public void Connection()
        {
            StateObject state = new StateObject();
            TcpClient cSocket = new TcpClient();
            Thread.Sleep(500);

            for (int i = 1; i < 10; i++)
            {
                if (Config.Good2Go)
                {
                    try
                    {
                        cSocket.Client.Connect(Config.ipaddress[Config.IP], 5330);
                        
                        Send(cSocket.Client, "*File|");

                        Receive_List(cSocket.Client);
                        return;
                        //Config.cSocket.Client.Shutdown(SocketShutdown.Both);
                        //Config.cSocket.Close();
                    }
                    catch (Exception e) { System.Diagnostics.Debug.Write(e.Message); }
                }
                else
                {
                    Marqee.ForeColor = System.Drawing.Color.Red;
                    Marqee.Text = "Connection Error: Retry " + i;
                }
            }
        }

        public void Receive_List(Object Client)
        {
            Socket client;
            byte[] buffer = new byte[1048 * 9999];
            if (Client == null)
            {
                TcpClient _Client = new TcpClient();
                _Client.Connect(Config.ipaddress[Config.IP], 5330);                                
                client = _Client.Client;
            }
            else client = (Socket)Client;
            int bytesRead;

            if (RemoteList.Items.Count > 0)
            {
                client.Send(Encoding.ASCII.GetBytes("*File|"));
                bytesRead = client.Receive(buffer);
                RemoteList.Items.Clear();
            }
            else bytesRead = client.Receive(buffer);
            
            var recieved = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            var stored = recieved.Split('=');

            for (int i = 0; i < stored.Length; i++)
            {
                if (stored[i].Contains("*File|"))
                {
                    Config.Info.Add(stored[i]);
                    RemoteList.Items.Add(Config.Info[i].ToString().Split('|')[1]);
                    Config.FileList.Add(Config.Info[i].ToString().Split('|')[1]);
                }
            }
            String news = stored[stored.Length - 1].Split('|')[1];
            Marqee.Text = news;
            RemoteList.SelectedIndex = 0;
        }
        public void Receive_File(object FilePath)
        {
            const int BUFFER_SIZE = 16 * 1024;
            using (var outputFileStream = File.Create(Config.RunningDirectory() + "/" + new FileInfo((string)RemoteList.SelectedItem).Name, BUFFER_SIZE))
            {
                var req = WebRequest.Create((string)FilePath);

                using (var response = req.GetResponse())
                {
                    progressBar1.Maximum = (int)response.ContentLength;

                    using (var responseStream = response.GetResponseStream())
                    {
                        var buffer = new byte[BUFFER_SIZE];
                        int bytesRead;
                        do
                        {
                            bytesRead = responseStream.Read(buffer, 0, BUFFER_SIZE);
                            UpdateProgress(bytesRead);
                            outputFileStream.Write(buffer, 0, bytesRead);
                        } while (bytesRead > 0);
                    }
                }
            }
            RemoteList.Enabled = true;
        }

        float bytesReceived;
        public void UpdateProgress(int bytesRead)
        {
            bytesReceived = (bytesReceived + bytesRead);
            float filesize = (float)progressBar1.Maximum / 1048576;
            progressBar1.Value = (int)bytesReceived;
            float percent = ((((float)progressBar1.Value) / (float)progressBar1.Maximum) * 100);

            ProgressLabel.Text = percent.ToString("###.##") + "%   |   " + 
                ((float)progressBar1.Value / 1048576).ToString("###.##") + " mb / " + 
                filesize.ToString("###.##") + "mb";
        }
        
        public void Send(Socket client, String data)
        {
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            client.Send(byteData, 0, byteData.Length, SocketFlags.None);
        }
        #endregion
    }
}